#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>

#include "core.h"
#include "../config/config.h"
#include "../conn/conn.h"


void parse_unitservice(void* user,const char *section,const char *key,char *value){
    Service_t *cmd=(Service_t*)user;
    if (strcmp(section,"Unit")==0 && strcmp(key,"Env")==0)
    {
        cmd->env=str_split(value,",",4096);
    }else if (strcmp(section,"Install")==0 && strcmp(key,"WantedBy")==0)
    {
        trim(value);
        cmd->wantedby=calloc(strlen(value)+1,1);
        strcpy(cmd->wantedby,value);
    }else if (strcmp(section,"Service")==0 && strcmp(key,"ExecStart")==0)
    {
        cmd->agrv=str_split(value," ",4096);
        cmd->binname=calloc(1024,1);
        cmd->binpath=calloc(4096,1);
        split_dir_file(NULL,cmd->binname,cmd->agrv[0]);
        strcpy(cmd->binpath,cmd->agrv[0]);
        strcpy(cmd->agrv[0],cmd->binname);
    }else if (strcmp(section,"Service")==0 && strcmp(key,"Stdin")==0)
    {
        trim(value);
        cmd->std_in=calloc(strlen(value)+1,1);
        strcpy(cmd->std_in,value);
    }else if (strcmp(section,"Service")==0 && strcmp(key,"Stdout")==0)
    {
        trim(value);
        cmd->std_out=calloc(strlen(value)+1,1);
        strcpy(cmd->std_out,value);
    }else if (strcmp(section,"Service")==0 && strcmp(key,"Stderr")==0)
    {
        trim(value);
        cmd->std_err=calloc(strlen(value)+1,1);
        strcpy(cmd->std_err,value);
    }else if (strcmp(section,"Service")==0 && strcmp(key,"Type")==0)
    {
        trim(value);
        if (strcmp(value,"notify")==0)
        {
            cmd->start_type=1;
        }else if (strcmp(value,"dbus")==0)
        {
            cmd->start_type=2;
        }else{
            cmd->start_type=0;
        }   
    }
}

void parse_unitsocket(void* user,const char *section,const char *key,char *value){
    Socket_t *unitsock=(Socket_t*)user;
    if (strcmp(section,"Unit")==0 && strcmp(key,"Service")==0)
    {
        trim(value);
        unitsock->service=calloc(strlen(value)+1,1);
        strcpy(unitsock->service,value);
    }else if (strcmp(section,"Socket")==0 && strcmp(key,"StreamPath")==0)
    {
        trim(value);
        unitsock->stream_path=calloc(strlen(value)+1,1);
        strcpy(unitsock->stream_path,value);
    }else if (strcmp(section,"Socket")==0 && strcmp(key,"DgramPath")==0)
    {
        trim(value);
        unitsock->dgram_path=calloc(strlen(value)+1,1);
        strcpy(unitsock->dgram_path,value);
    }
}


void parse_unittarget(void* user,const char *section,const char *key,char *value){
    Target_t *target=(Target_t*)user;
    if ((strcmp(section,"Install")==0) && (strcmp(key,"WantedBy")==0))
    {
        trim(value);
        // printf("parse_target(): value: %s\n",value);
        target->wantedby=calloc(strlen(value)+1,1);
        strcpy(target->wantedby,value);
        // printf("parse_target(): %s\n",level->wantedby);
    }
}


// 根据service unit成一个service
int uintservice_generate(Service_t *svc,const char *dir,const char *file){
    if (svc==NULL || dir==NULL || file==NULL)
    {
        return -1;
    }
    memset(svc,0,sizeof(Service_t));
    svc->conf_dir=calloc(4096,1);
    strcpy(svc->conf_dir,dir);
    svc->conf_file=calloc(4096,1);
    strcpy(svc->conf_file,file);
    char path[4096];
    strcpy(path,dir);
    strcat(path,"/");
    strcat(path,file);
    split_dir_file(svc->conf_dir,svc->conf_file,path);
    if (ini_parse(svc,path,parse_unitservice,&svc->conf_lastmtime)<0)
    {
        printf("Error: parse %s failed\n",path);
        return -1;
    }
    return 0;
}
// 根据socket unit成一个socket
int unitsocket_generate(Socket_t *sock,const char *dir,const char *file){
    if (sock==NULL || dir==NULL || file==NULL)
    {
        return -1;
    }
    memset(sock,0,sizeof(Socket_t));
    sock->conf_dir=calloc(4096,1);
    strcpy(sock->conf_dir,dir);
    sock->conf_file=calloc(4096,1);
    strcpy(sock->conf_file,file);
    char path[4096];
    strcpy(path,dir);
    strcat(path,"/");
    strcat(path,file);
    if (ini_parse(sock,path,parse_unitsocket,&sock->conf_lastmtime)<0)
    {
        printf("Error: parse %s failed\n",path);
        return -1;
    }
    return 0;
}

int unittarget_generate(Target_t *target,const char *dir,const char *file){
    if (target==NULL||dir==NULL||file==NULL)
    {
        return -1;
    }
    target->conf_dir=calloc(4096,1);
    strcpy(target->conf_dir,dir);
    target->conf_file=calloc(4096,1);
    strcpy(target->conf_file,file);
    target->name=target->conf_file;
    char path[4096];
    strcpy(path,dir);
    strcat(path,"/");
    strcat(path,file);
    if (ini_parse(target,path,parse_unittarget,&target->conf_lastmtime)<0)
    {
        printf("Error: parse %s failed\n",path);
        return -1;
    }
    return 0;
}

Task_t *lookup_task(Target_t *target,int pid,const char *service){
    if (target==NULL)
    {
        return NULL;
    }

    Target_t *now=target;
    do
    {
        for (size_t i = 0; i < now->taskslen; i++)
        {
            if (now->tasks[i].status.pid==pid || strcmp(now->tasks[i].service.conf_file,service)==0)
            {
                return &now->tasks[i];
            }
        }
        now=(Target_t*)now->next;
    } while (now);
    return NULL;
}

// 合并service,socket成target
void merge_target(Target_t *target){
    char dir[4096];
    strcpy(dir,target->conf_dir);
    strcat(dir,"/");
    strcat(dir,target->conf_file);
    strcat(dir,".");
    strcat(dir,"wants");
    char **svcfiles=load_dir(dir,".service");
    if (svcfiles==NULL)
    {
        return;
    }
    char **socfiles=load_dir(dir,".socket");
    target->taskslen=0;
    target->tasks=NULL;
    while (svcfiles[target->taskslen]!=NULL)
    {
        //加载service文件
        target->tasks=realloc(target->tasks,(target->taskslen+1)*sizeof(Task_t));
        memset(&target->tasks[target->taskslen],0,sizeof(Task_t));
        uintservice_generate(&target->tasks[target->taskslen].service,dir,svcfiles[target->taskslen]);
        target->tasks[target->taskslen].sockets=NULL;
        target->taskslen++;
    }
    Socket_t sock;
    memset(&sock,0,sizeof(Socket_t));
    if (socfiles!=NULL)
    {
        int i=0;
        while (socfiles[i])
        {
            //加载socket文件
            unitsocket_generate(&sock,dir,socfiles[i]);
            i++;
            for (size_t j = 0; j < target->taskslen; j++)
            {
                if (strcmp(target->tasks[j].service.conf_file,sock.service)==0)
                {
                    target->tasks[j].socketslen++;
                    target->tasks[j].sockets=realloc(target->tasks[j].sockets,target->tasks[j].socketslen*sizeof(Socket_t));
                    target->tasks[j].sockets[target->tasks[j].socketslen-1]=sock;
                    // printf("service:%s path:%s\n",target->tasks[j].sockets[target->tasks[j].socketslen-1].service,target->tasks[j].sockets[target->tasks[j].socketslen-1].stream_path);
                    break;
                }
            
            }
        }
        str_free(socfiles);
    }
    str_free(svcfiles); 
}


bootm_t *bootm_init(const char* dir,const char *__default__){
    if (dir==NULL||__default__==NULL)
    {
        return NULL;
    }
    
    bootm_t *bootm=calloc(sizeof(bootm_t),1);
    bootm->flag=1;
    const char *now_target;
    Target_t   *now=NULL;
    //Target_t   *upper=NULL;
    //default target
    now_target=__default__;

    do
    {
        now=calloc(sizeof(Target_t),1);
        if (bootm->lower==NULL)
        {
            bootm->lower=now;
        }
        
        int ret=unittarget_generate(now,dir,now_target);
        if (ret>=0)
        {
            bootm->curr_num++;
            merge_target(now);
            if (now->wantedby!=NULL)
            {
                //printf("gen_taerget(): now=%s want=%s\n",next_target->name,next_target->wantedby);
                now_target=now->wantedby;
                if (bootm->upper!=NULL)
                {
                    bootm->upper->last=now;
                    now->next=bootm->upper;
                }
                bootm->upper=now;
            }else{
                if (bootm->upper!=NULL)
                {
                    bootm->upper->last=now;
                    now->next=bootm->upper;
                    bootm->upper=now;
                    printf("[\033[3;32m  ok  \033[0m] Load %s (1/%d) -- init target.\n",bootm->upper->name,bootm->curr_num);
                }
                bootm->now=bootm->upper;
                // bootm->lower->next=bootm->upper;
                // bootm->upper->last=bootm->lower;
                return bootm;
            }
        }else{
            printf("[\033[3;32m  ok  \033[0m] Load %s Error -- Current target -> %s (1/%d).\n",now_target,bootm->upper->name,bootm->curr_num);
            now_target=NULL;
        }
    } while (now_target!=NULL);
    bootm->now=bootm->upper;
    return bootm;
}
